#include "scene.h"
#include "./objects/ground.h"
#include "./objects/crate.h"
#include "./objects/clamp.h"
#include "./objects/truck.h"
#include "./objects/cloud.h"

Scene::Scene()
	: gravity(9.8),sceneRec(0.0f,1200.0f,0.0f,600.0f){
}

void Scene::createClouds(){
	/*CloudB* cloudB=new CloudB(Rectangle(800.0f,900.0f,100.0f,150.0f));//(Rectangle(400.0f,550.0f,100,150));
	listObject.push_back(cloudB);
*/
	CloudB* cloudB2=new CloudB(Rectangle(600.0f,700.0f,150.0f,200.0f));//(Rectangle(400.0f,550.0f,100,150));
	listObject.push_back(cloudB2);

	CloudA* cloudA=new CloudA(Rectangle(200.0f,300.0f,80.0f,140.0f));//(Rectangle(400.0f,550.0f,100,150));
	listObject.push_back(cloudA);

	CloudA* cloudA2=new CloudA(Rectangle(450.0f,550.0f,250.0f,300.0f));//(Rectangle(400.0f,550.0f,100,150));
	listObject.push_back(cloudA2);
}

void Scene::createCrates(){
	Crate* cr[8];
	cr[0]= new Crate(Rectangle(800.0f,850.0f,60.0f,100.0f),CrateViewB::instance());
	listObject.push_back(cr[0]);

	cr[1]= new Crate(Rectangle(700.0f,780.0f,60.0f,110.0f),CrateViewB::instance());
	listObject.push_back(cr[1]);

	cr[2]= new Crate(Rectangle(900.0f,930.0f,60.0f,85.0f),CrateViewA::instance());
	listObject.push_back(cr[2]);

	cr[3] = new Crate(Rectangle(950.0f,1000.0f,60.0f,105.0f),CrateViewA::instance());
	listObject.push_back(cr[3]);

	cr[4] = new Crate(Rectangle(1015.0f,1085.0f,60.0f,95.0f),CrateViewC::instance());
	listObject.push_back(cr[4]);

	cr[5]= new Crate(Rectangle(1100.0f,1150.0f,60.0f,85.0f),CrateViewC::instance());
	listObject.push_back(cr[5]);

	cr[6] = new Crate(Rectangle(700.0f,760.0f,500.0f,550.0f),CrateViewA::instance());
	listObject.push_back(cr[6]);

	Clamp& clamp = helicopter->getClamp();
	for (int i=0;i<7;i++){
		clamp.addGrabable(cr[i]);
		gravity.addSolid(cr[i]);

	}
}

Scene::~Scene(){
	for(std::list<SceneObject*>::iterator it=listObject.begin();it!=listObject.end();++it){
		delete *it;
	}
}

void Scene::display(){
	Framework& fr = Framework::instance();
	fr.pipeline.loadIdentity();

	for(std::list<SceneObject*>::iterator it=listObject.begin();it!=listObject.end();){
		if(!(*it)->isKilled()){
			(*it)->draw();
			++it;
		}else{
			SceneObject* obj=*it;
			it=listObject.erase(it);
			gravity.removeSolid(static_cast<Crate*>(obj));
			delete(obj);
		}
	}
	limitHelicopter();
}

void Scene::limitHelicopter(){
	if( 	((helicopter->getDimensions().x1<this->sceneRec.x1) && (helicopter->getSpeed()<0)) ||
			((helicopter->getDimensions().x2>this->sceneRec.x2) && helicopter->getSpeed()>0) )
       helicopter->stopX();
   if(	((helicopter->getDimensions().y1<this->sceneRec.y1) && (helicopter->getSpeedy()<0))||
		((helicopter->getClamp().getDimensions().y2>this->ground->getDimensions().y1) && (helicopter->getSpeedy()>0)) )
	   helicopter->stopY();

}

void Scene::timer(int value){
	gravity.advanceTime();
	for(std::list<SceneObject*>::iterator it=listObject.begin();it!=listObject.end();++it){
		(*it)->timeStep();
	}


	Framework& fr = Framework::instance();

	Clamp& clamp = helicopter->getClamp();
	if(clamp.isClosed() && clamp.getGrabbed()){
		Crate* grabbed = static_cast<Crate*>(clamp.getGrabbed());
		listObject.remove(grabbed);
		gravity.removeSolid(grabbed);
		grabbed->setGrabbed(true);
	}
	centerScreen();

	fr.redisplay();
}

void Scene::centerScreen(){
	Framework& fr = Framework::instance();
	// No centras si se pasa del limite
	if(helicopter->getDimensions().centerX()>=300)
		if(helicopter->getDimensions().centerX()>900)
			fr.pipeline.worldWindow(sceneRec.y2,600,1200,sceneRec.y1);
		else
			fr.pipeline.worldWindow(sceneRec.y2,helicopter->getDimensions().centerX()-300,helicopter->getDimensions().centerX()+300,sceneRec.y1);
	else
		fr.pipeline.worldWindow(sceneRec.y2,0,600,sceneRec.y1);
}

void Scene::specKeyboard(int key,int x ,int y){
	Framework& fr = Framework::instance();
	switch (key){
		case 0x1b:
			exit (1);
			break;
		case GLUT_KEY_LEFT:
            if (helicopter->getDimensions().x1>this->sceneRec.x1){
                helicopter->accelerateX(Helicopter::LEFT);
                fr.redisplay();
            }
			break;
		case GLUT_KEY_UP:
		    if (helicopter->getDimensions().y1>this->sceneRec.y1){
                helicopter->accelerateY(Helicopter::UP);
                fr.redisplay();
            }
			break;
		case GLUT_KEY_RIGHT:
		     if (helicopter->getDimensions().x2<this->sceneRec.x2){
                helicopter->accelerateX(Helicopter::RIGHT);
                fr.redisplay();
            }
			break;
		case GLUT_KEY_DOWN:
		    if (helicopter->getClamp().getDimensions().y2<this->ground->getDimensions().y1){
                helicopter->accelerateY(Helicopter::DOWN);
                fr.redisplay();
            }
			break;
	}
}

void Scene::keyboard(unsigned char key,int x ,int y){
	switch (key){
		case 0x1b:
			exit (1);
			break;
		case 'p':
			handleClamp();
			break;

		case 'a':
			helicopter->moveClamp(Thread::UP);
			break;

		case 'z':
            if (helicopter->getClamp().getDimensions().y2<this->ground->getDimensions().y1)
                helicopter->moveClamp(Thread::DOWN);
			break;

		case 'r':
			restart();
			break;
	}
}

void Scene::handleClamp(){
	Clamp& clamp=helicopter->getClamp();
	if (clamp.isClosed()){
		helicopter->openClamp();
		if(clamp.getGrabbed()){
			Crate* grabbed = static_cast<Crate*>(clamp.release());
			clamp.getObject(Grabable::name());
			listObject.push_back(grabbed);
			gravity.addSolid(grabbed);
			grabbed->setGrabbed(false);
		}
	}else{
		helicopter->closeClamp();
	}
}

void Scene::restart(){
	for(std::list<SceneObject*>::iterator it=listObject.begin();it!=listObject.end();++it){
		delete *it;
	}
	listObject.clear();
	gravity.clear();

	init();
}

void Scene::init(){
	Framework& fr = Framework::instance();
	fr.setClearColor(0.48f,0.79f,1.0f);

	createClouds();

	helicopter = new Helicopter(Rectangle(0.0f,200.0f,0.0f,100.0f),
								Rectangle(100.0f,100.0f,60.0f,150.0f),
								Rectangle(85.0f-5,115.0f+5,132.5f-5,162.5f+5));

	helicopter->move(600.0f,0.0f);
	listObject.push_back(helicopter);

	CloudB* cloudB=new CloudB(Rectangle(800.0f,900.0f,100.0f,150.0f));//(Rectangle(400.0f,550.0f,100,150));
	listObject.push_back(cloudB);


	ground = new Ground(Rectangle(sceneRec.x1,sceneRec.x2,590,600));
	listObject.push_back(ground);

	Truck* truck = new Truck( Rectangle(0.0f,100.0f,450.0f,565.0f),
							  Rectangle(50.0f,150.0f,35.0f,57.0f));

	listObject.push_back(truck);

	createCrates();
	gravity.addSolid(ground);
	gravity.addSolid(truck);

	this->centerScreen();
}
